package com;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.io.Files;
import com.google.common.util.concurrent.Uninterruptibles;
import io.airlift.airline.Command;
import io.airlift.airline.HelpOption;
import jline.console.completer.StringsCompleter;
import jline.console.history.FileHistory;
import jline.console.history.History;
import jline.console.history.MemoryHistory;
import jline.internal.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.AnsiConsole;

import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author 张述江
 * @date 2023-08-28
 */
@Command(name = "demo", description = "主要的描述语句")
public class Console {
    @Inject // javax.inject.Inject;
    public HelpOption helpOption;

    // 不知为何，VersionOption无法自动实现依赖注入，需要手动创建，且无法去除@Inject注解
    @Inject
    public VersionOption versionOption = new VersionOption();

    @Inject
    public ClientOptions clientOptions;

    /**
     * 简单打印client options的值
     */

    public boolean run() {
        AnsiConsole.systemInstall();

        AtomicBoolean exiting = new AtomicBoolean();
        ThreadInterruptor interruptor = new ThreadInterruptor();
        CountDownLatch exited = new CountDownLatch(1);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            exiting.set(true);
            interruptor.interrupt();
            Uninterruptibles.awaitUninterruptibly(exited, 1000, TimeUnit.MILLISECONDS);
        }));

        try {
            runConsole(exiting);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    private static MemoryHistory getHistory() {
        String historyFilePath = System.getenv("DEMO_HISTORY_FILE");
        File historyFile;
        if (Strings.isNullOrEmpty(historyFilePath)) {
            historyFile = new File(Configuration.getUserHome(), ".demo_history");
        } else {
            historyFile = new File(historyFilePath);
        }

        return getHistory(historyFile);
    }

    @VisibleForTesting
    static MemoryHistory getHistory(File historyFile) {
        MemoryHistory history;
        try {
            Files.createParentDirs(historyFile.getParentFile());
            historyFile.createNewFile();
            history = new FileHistory(historyFile);
            history.setMaxSize(10000);
        } catch (IOException var3) {
            System.err.printf("WARNING: Failed to load history file (%s): %s. History will not be available during this session.%n", historyFile, var3.getMessage());
            history = new MemoryHistory();
        }

        history.setAutoTrim(true);
        return history;
    }

    private void runConsole(AtomicBoolean exiting) throws IOException {
        // 用于提示和自动完成
        StringsCompleter stringsCompleter = new StringsCompleter("help", "head", "foreach", "dict", "hidden");
        MemoryHistory history = getHistory();
        try (LineReader reader = new LineReader(history, stringsCompleter)) {

            while (!exiting.get()) {
                String prompt = "demo";
                String commandPrompt = prompt + "> ";

                String line = reader.readLine(commandPrompt);
                if (reader.interrupted()) {
                    break;
                } else {
                    if (StringUtils.isBlank(line)) {
                        continue;
                    }
                    history.add(line);
                    if ("exit".equalsIgnoreCase(line)) {
                        break;
                    }
                    if ("history".equalsIgnoreCase(line)) {
                        for (History.Entry entry : history) {
                            System.out.printf("%5d  %s%n", entry.index() + 1, entry.value());
                        }
                        continue;
                    }
                    if ("help".equalsIgnoreCase(line)) {
                        helpOption.showHelpIfRequested();
                        continue;
                    }
                    Ansi content = Ansi.ansi().eraseScreen().fg(Ansi.Color.GREEN).a(line).reset();
                    System.out.println(content);
                }
            }
        }
    }
}
